/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/

#include <stdio.h>
#include <io.h>
#include <Fcntl.h>
#include <sys/stat.h>

#include "StdAfx.h"
#include "mstore.h"
#include "O_IMSProvider.h"

#include "otlkcon_debug.h"
#include "otlkcon_event.h"

#include <AllocProfiler/AllocProfiler.h>

#include <mspst.h>

#ifdef _DEBUG
#include "crtdbg.h"
#endif

wchar_t otlkcon_logFile[MAX_PATH+1]        = {0};
int  otlkcon_logToFileEnabled   = 1;
int  otlkcon_logToSMEnabled     = 0;
int  otlkcon_logToMSVCEnabled   = 0;
DWORD otlkcon_eventThreadId     = 0;
HWND  otlkcon_eventHwnd         = 0;

sqlite3 *sqlObjHandle = NULL;

// A global list of objects that can send/receive messages
map< O_ENTRYID *, void *, otlkcon_entryid_less > otlkcon_event_objects;
CRITICAL_SECTION    otlkcon_objects_cs;

//int  otlkcon_debugLevel           = OTLKCON_LOG_LEVEL_SPECIAL_1;
int  otlkcon_debugLevel          = OTLKCON_DEFAULT_DEBUGLEVEL;

DWORD  otlkcon_tlsIndex = (DWORD)-1; //default value;
CRITICAL_SECTION otlkcon_sqlite_cs;

//Process global: list of all open msgstores
//Henry 30.12.2005 istead of stores we need to keep list of MSProvider objects
//List of stores should be local to every provider object
//Provider object contains context
//vector<otlkcon_generic_msgstore *> otlkcon_stores;
CRITICAL_SECTION otlkcon_stores_cs;

// INFO:  This is for the sake of the transport provider.
//        In the future we can find out if there is a
//        better way of having the two providers communicate.
vector<O_IMSProvider *> otlkcon_store_providers;
CRITICAL_SECTION otlkcon_store_providers_cs;

// Set of folders waiting for an XPP to initialize
map< O_ENTRYID *, O_IContainer *, otlkcon_entryid_less > otlkcon_xpp_wait_set;
CRITICAL_SECTION otlkcon_xpp_wait_set_cs;

#ifdef OTLKCON_LOG_SM_SUPPORT_ENABLED
debugServerContext *otlkcon_processSMServerContext = 0;
#endif

HRESULT OpenProviderProfileSection(
	LPPROVIDERADMIN pAdminProvObj,
	ULONG			ulProviderType,
	LPPROFSECT *    ppProfSectObj
	);

HRESULT O_MessageServiceInit(LPALLOCATEBUFFER lpAllocateBuffer);

// MSGSERVICEENTRY implementation
HRESULT STDAPICALLTYPE O_ServiceEntry(HINSTANCE hInstance,
	LPMALLOC lpMalloc, 
	LPMAPISUP lpMAPISup,
	ULONG ulUIParam,
	ULONG ulFlags,
	ULONG ulContext,
	ULONG cValues,
	LPSPropValue lpProps,
	LPPROVIDERADMIN lpProviderAdmin,
	LPMAPIERROR *lppMapiError)
{
    HRESULT result = S_OK;

	if(NULL != lppMapiError)
	{
		*lppMapiError = NULL;
	} // if

	LPALLOCATEBUFFER lpAllocateBuffer = NULL;
	LPALLOCATEMORE lpAllocateMore = NULL;
	LPFREEBUFFER lpFreeBuffer = NULL;
	lpMAPISup->GetMemAllocRoutines(&lpAllocateBuffer, &lpAllocateMore, &lpFreeBuffer);
	otlkcon_memory memObj( lpAllocateBuffer, lpAllocateMore, lpFreeBuffer ); 

	//debugObj.Initialize(lpAllocateBuffer, lpFreeBuffer);
	O_MessageServiceInit(lpAllocateBuffer);

	BOOL bUIAllowed = (SERVICE_UI_ALLOWED & ulFlags) ||
		(SERVICE_UI_ALWAYS & ulFlags);
	BOOL bUIAlways = SERVICE_UI_ALWAYS & ulFlags;

    switch(ulContext)
    {
         case MSG_SERVICE_CONFIGURE:
			{
				
				if(SERVICE_UI_ALLOWED & ulFlags ||
					SERVICE_UI_ALWAYS & ulFlags)
                {
                } // if
				
                otlkcon_memory *confMem = new otlkcon_memory( &memObj );
				otlkcon_config *conf = new otlkcon_config((HWND)ulUIParam, confMem);

				OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
					L"inside MSG_SERVICE_CONFIGURE.\n");

				LPPROFSECT lpProfileObj = NULL;
                LPPROFSECT lpServiceProfileObj = NULL;
                ULONG profPropsCount = 0;
				SizedSPropTagArray(50, profTags);
				memset(&profTags,0, sizeof(profTags));	
				LPENTRYID profEID = NULL;
				LPSPropValue profProps = NULL;
                wchar_t strBuffW[MAX_PATH+1] = {0};
                char strBuff[MAX_PATH+1] = {0};
				char      *profProviderDisplay = NULL, *profdataFile = NULL;
				MAPIUID   *profMdbProvider = NULL, *profServiceUid = NULL, *profRecordKey = NULL;

                SPropValue tempProps[50] = {0};
				ULONG ulProps = 0;
                SBinary sbWrappedEntryID = {0};
                otlkcon_event_struct *event = NULL;

				result = OpenProviderProfileSection(lpProviderAdmin, MAPI_STORE_PROVIDER, &lpProfileObj);
				if(SUCCEEDED(result))
				{
					profPropsCount = 0;
					memset(&profTags,0, sizeof(profTags));

					// If any of the following properties exist, we should use those
					// instead of generating new values??  If they do not exist, then
					// generate new values??

					profTags.aulPropTag[profPropsCount++] = PR_ENTRYID;
					profTags.aulPropTag[profPropsCount++] = PR_PROVIDER_DISPLAY;
					profTags.aulPropTag[profPropsCount++] = PR_MDB_PROVIDER;
					profTags.aulPropTag[profPropsCount++] = PR_RECORD_KEY;
					profTags.aulPropTag[profPropsCount++] = PR_SERVICE_UID;
					profTags.aulPropTag[profPropsCount++] = PR_PROVIDER_UID;
					profTags.aulPropTag[profPropsCount++] = PR_PST_PATH;
					profTags.cValues = profPropsCount;

					result = lpProfileObj->GetProps(
						(LPSPropTagArray)&profTags,
						0, &profPropsCount,
						&profProps);
					switch( result )
					{
					case MAPI_W_ERRORS_RETURNED:
					case S_OK:			
						for( ULONG i=0; i<profPropsCount; i++ )
						{
							if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_ENTRYID) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
								{
									profEID = (LPENTRYID)(profProps[i].Value.bin.lpb);
								}    
							}
							else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_PROVIDER_DISPLAY) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
									profProviderDisplay = _strdup(profProps[i].Value.lpszA);
								}
							}
							else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_MDB_PROVIDER) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
								{
									profMdbProvider =  (MAPIUID*)(profProps[i].Value.bin.lpb);
									if( memcmp(profMdbProvider, &otlkcon_mdb_provider_guid, sizeof(MAPIUID)) )
									{
										OTLKCON_DEBUGBREAK;
									}
								}
							}
							else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_RECORD_KEY) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
								{
									profRecordKey = (LPMAPIUID)(profProps[i].Value.bin.lpb);
								}
							}
							else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_SERVICE_UID) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
								{
									profServiceUid = (MAPIUID*)(profProps[i].Value.bin.lpb);
								}
							}
							else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_PST_PATH) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    wchar_t dbFilenameBuff[MAX_PATH+1] = {0};
                                    _snwprintf_s( dbFilenameBuff, MAX_PATH+1,
                                        MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->dbFilename = dbFilenameBuff;
								}
							}
						}
						break;

					default:
						//Error condition
						// Call failed 
						OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
							L"GetProfileProperties: GetProps failed.\n" );
						result = MAPI_E_UNCONFIGURED;
					}
                }
                else
                {
                    // OpenProviderProfileSection failed
                    OTLKCON_DEBUGBREAK;
                }
					
                if( profServiceUid == NULL )
                {
                    // We did not get the service UID
                    OTLKCON_DEBUGBREAK;
                }

                result = lpProviderAdmin->OpenProfileSection(profServiceUid, NULL, MAPI_MODIFY,
                                    &lpServiceProfileObj);
                if( FAILED(result) )
                {
                    // This may happen depending on the context
                    result = lpProviderAdmin->OpenProfileSection(NULL, NULL, MAPI_MODIFY,
                                    &lpServiceProfileObj);
                }
               // result = OpenProviderProfileSection(lpProviderAdmin, 
                //    MAPI_TRANSPORT_PROVIDER, &lpXPProfileObj);
				if(SUCCEEDED(result))
				{
					memset(&profTags,0, sizeof(profTags));
					profPropsCount = 0;

					// If any of the following properties exist, we should use those
					// instead of generating new values??  If they do not exist, then
					// generate new values??
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_XP_ENABLED;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_AB_ENABLED;

                    // FIXME: Switch to otlkcon_getAccountsData()

                    // Account info
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_1;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_1;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_1;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_1;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_1;
                    profTags.aulPropTag[profPropsCount++] 
                                                = PR_OTLKCON_ACCOUNT_AB_ENABLE_1;
                    profTags.aulPropTag[profPropsCount++] 
                                                = PR_OTLKCON_ACCOUNT_USERNAME_1;
                    profTags.aulPropTag[profPropsCount++] 
                                                = PR_OTLKCON_ACCOUNT_PASSWORD_1;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_1;
                    profTags.aulPropTag[profPropsCount++] 
                                                = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_1;

                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_2;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_2;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_2;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_2;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_2;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_AB_ENABLE_2;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_USERNAME_2;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PASSWORD_2;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_2;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2;

                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_3;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_3;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_3;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_3;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_3;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_AB_ENABLE_3;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_USERNAME_3;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PASSWORD_3;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_3;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3;

                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_4;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_4;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_4;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_4;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_4;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_AB_ENABLE_4;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_USERNAME_4;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PASSWORD_4;
                    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_4;
                    profTags.aulPropTag[profPropsCount++] 
                                                    = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4;

					profTags.cValues = profPropsCount;

                    for( int i=0; i<OTLKCON_ACCOUNT_MAX; i++)
                    {
                        conf->accounts.push_back( new otlkcon_account_details() );
                    }

					result = lpServiceProfileObj->GetProps(
						(LPSPropTagArray)&profTags,
						0, &profPropsCount,
						&profProps);
					switch( result )
					{
					case MAPI_W_ERRORS_RETURNED:
					case S_OK:			
						for( ULONG i=0; i<profPropsCount; i++ )
						{
							if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_XP_ENABLED) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->xpEnabled = profProps[i].Value.b;
								}
							}
                            if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_AB_ENABLED) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->abEnabled = profProps[i].Value.b;
								}
							}// Account 1
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                            MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->id = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
								{
                                    conf->accounts[0]->type = profProps[i].Value.l;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1, 
                                        MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->name = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                        MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->user = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->pass = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->uri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                        == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[0]->principleUri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[0]->enabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                          == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[0]->abEnabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_1) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[0]->defaultAccount 
                                        = profProps[i].Value.b;
								}
							}// Account 2
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->id = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
								{
                                    conf->accounts[1]->type = profProps[i].Value.l;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->name = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->user = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->pass = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->uri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                        == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[1]->principleUri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[1]->enabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                          == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[1]->abEnabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_2) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[1]->defaultAccount 
                                        = profProps[i].Value.b;
								}
							}// Account 3
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->id = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
								{
                                    conf->accounts[2]->type = profProps[i].Value.l;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->name = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->user = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->pass = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->uri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                        == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[2]->principleUri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[2]->enabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                          == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[2]->abEnabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_3) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[2]->defaultAccount 
                                        = profProps[i].Value.b;
								}
							} //Account 4
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->id = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
								{
                                    conf->accounts[3]->type = profProps[i].Value.l;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->name = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->user = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->pass = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->uri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                        == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
								{
                                    _snwprintf_s( strBuffW, MAX_PATH+1,
                                         MAX_PATH, L"%S", 
									            profProps[i].Value.lpszA);
                                    conf->accounts[3]->principleUri = strBuffW;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[3]->enabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                          == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[3]->abEnabled = profProps[i].Value.b;
								}
							}
                            else if( PROP_ID(profProps[i].ulPropTag) 
                                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_4) )
							{
								if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
								{
                                    conf->accounts[3]->defaultAccount 
                                        = profProps[i].Value.b;
								}
							}
						}
						break;

					default:
						//Error condition
						// Call failed 
						OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
							L"GetProfileProperties: GetProps failed.\n" );
						result = MAPI_E_UNCONFIGURED;
					}

                    // Delete unused account structs
                    for( vector<otlkcon_account_details*>::iterator i 
                                                           = conf->accounts.begin();
                        i != conf->accounts.end(); )
                    {
                        if( (*i)->id.empty() )
                        {
                            // FIXME: Test that this works in VS 2003
                            //        VS 2005 made the previous behavior
                            //        illegal.
                            i = conf->accounts.erase( i );
                        }
                        else
                        {
                            ++i;
                        }
                    }
                }
                else
                {
                    // OpenProfileSection for service failed
                    OTLKCON_DEBUGBREAK;
                }

                // Display the configure gui with the values just
                // pulled from the profile.
				//if(bUIAlways || (bNeedAdditionalInfo && bUIAllowed))
                if( bUIAllowed )
				{
					//Henry: TODO
					//if properties passed to the O_ServiceEntry
					//we should use them too
					result = conf->showGui();
				} // if
				else
				{
					result = MAPI_E_UNCONFIGURED;
				} // else

                if( conf->isDirty && S_OK == result )
				{
					// Set profiles properties from gui.

                    // FIXME: Notify all message stores and transport
                    //        providers that the config has to be
                    //        reloaded.  OTLKCON_EVENT_RELOAD_CONFIG

                    if( conf->accountIdChanges.size() > 0 )
                    {
                        // Serialize map
                        ULONG mapSize = 0;
                        for( map<wstring,wstring>::iterator i=conf->accountIdChanges.begin();
                            i!= conf->accountIdChanges.end(); ++i)
                        {
                            mapSize += (ULONG)(i->first.length()) + 1;
                            mapSize += (ULONG)(i->second.length()) + 1;
                        }
                        mapSize *= sizeof(wchar_t);

                        wchar_t *acctIdStr = (wchar_t *)memObj.pMalloc( mapSize );
                        wchar_t *acctIdStrTmp = acctIdStr;

                        for( map<wstring,wstring>::iterator i=conf->accountIdChanges.begin();
                            i!= conf->accountIdChanges.end(); ++i)
                        {
                            wcscpy_s(acctIdStrTmp, mapSize, i->first.c_str() );
                            acctIdStrTmp += i->first.length() + 1; 

                            wcscpy_s(acctIdStrTmp, 
                                mapSize-wcslen(i->first.c_str()+1),
                                i->second.c_str() );
                            acctIdStrTmp += i->second.length() + 1; 
                        }

                        event 
                            = (otlkcon_event_struct *)memObj.pMalloc(sizeof(otlkcon_event_struct)+mapSize );
                        
                        event->cbData            = mapSize;
                        memcpy(&(event->data), acctIdStr, mapSize);
                        memObj.pFree( acctIdStr);
                      
                        // Inform the message store provider of those event found on the remote server
                        event->eventType = OTLKCON_EVENT_RELOAD_CONFIG;
                        
                        for( map< O_ENTRYID *, void *, otlkcon_entryid_less >::iterator i
                            = otlkcon_event_objects.begin(); i!=otlkcon_event_objects.end();
                            ++i )
                        {
                            // Pass serialized id changes in the message body
                            // If the type is a store, or its an account.
                            if( i->first->typeID == MAPI_STORE 
                                || i->first->primarySupportedInterface 
                                            == OTLKCON_IXPLOGONACCOUNT_CLASS )
                            {
                                memcpy(&(event->entryID), i->first, sizeof(O_ENTRYID));
                                result = otlkcon_event_sendmessage( otlkcon_eventHwnd, 
                                    otlkcon_eventHwnd, event );
                            }
                        }
                        
                        memObj.pFree( event );
                    }

                    // PR_PST_PATH
                    _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                    conf->dbFilename.c_str());
					tempProps[ulProps].ulPropTag = PR_PST_PATH;
                    tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                    result = lpProfileObj->SetProps(ulProps, tempProps, NULL);
					result = lpProfileObj->SaveChanges(0);

                    ulProps = 0;

                    // FIXME:  The path really should be stored in a single
                    //         location.  But now that the address book needs
                    //         it, it has to show up in the session scope.
                    //         This breaks, having multiple message stores with
                    //         different paths it seems.  This will have to
                    //         be addressed later.
					tempProps[ulProps].ulPropTag = PR_PST_PATH;
                    tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                    // PR_OTLKCON_XP_ENABLED
                    tempProps[ulProps].ulPropTag = PR_OTLKCON_XP_ENABLED;
                    tempProps[ulProps++].Value.b = conf->xpEnabled;

                    // PR_OTLKCON_AB_ENABLED
                    tempProps[ulProps].ulPropTag = PR_OTLKCON_AB_ENABLED;
                    tempProps[ulProps++].Value.b = conf->abEnabled;

                    // Account 1
                    if( conf->accounts.size() > 0 )
                    {
                        _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                conf->accounts[0]->id.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ID_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_TYPE_1;
                        tempProps[ulProps++].Value.l = conf->accounts[0]->type;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                conf->accounts[0]->name.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_NAME_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_DEFAULT_1;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[0]->defaultAccount;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_AB_ENABLE_1;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[0]->abEnabled;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ENABLE_1;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[0]->enabled;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                conf->accounts[0]->user.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_USERNAME_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                conf->accounts[0]->pass.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_PASSWORD_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[0]->uri.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_URI_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                            conf->accounts[0]->principleUri.c_str());
						tempProps[ulProps].ulPropTag 
                                        = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_1;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);
                    }
                    else
                    {
                        // Currently the first account is never deleted.
                        ;
                    }

                    // Account 2
                    if( conf->accounts.size() > 1 )
                    {
                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[1]->id.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ID_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_TYPE_2;
                        tempProps[ulProps++].Value.l = conf->accounts[1]->type;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[1]->name.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_NAME_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_DEFAULT_2;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[1]->defaultAccount;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_AB_ENABLE_2;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[1]->abEnabled;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ENABLE_2;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[1]->enabled;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[1]->user.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_USERNAME_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[1]->pass.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_PASSWORD_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[1]->uri.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_URI_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                            conf->accounts[1]->principleUri.c_str());
						tempProps[ulProps].ulPropTag 
                                        = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);
                    }
                    else
                    {
                        // Delete account 2 in the profile if it
                        // exists.
                        int acctCount = 0;
                        SizedSPropTagArray( 10, acctProps);

                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ID_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_TYPE_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_NAME_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ENABLE_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_USERNAME_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_URI_2;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2;
                        acctProps.cValues = acctCount;

                        result 
                            = lpServiceProfileObj->DeleteProps( 
                                    (LPSPropTagArray)&acctProps, NULL );

                        // FIXME:  We need to delete the calendar folder
                        //         for this account.  Also
                        //         'UnRegisterAppointmentFolder' in MSP
                        //         message store.
                    }

                    // Account 3
                    if( conf->accounts.size() > 2 )
                    {
                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[2]->id.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ID_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_TYPE_3;
                        tempProps[ulProps++].Value.l = conf->accounts[2]->type;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[2]->name.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_NAME_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_DEFAULT_3;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[2]->defaultAccount;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_AB_ENABLE_3;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[2]->abEnabled;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ENABLE_3;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[2]->enabled;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[2]->user.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_USERNAME_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[2]->pass.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_PASSWORD_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[2]->uri.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_URI_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                            conf->accounts[2]->principleUri.c_str());
						tempProps[ulProps].ulPropTag 
                                        = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);
                    }
                    else
                    {
                        // Delete account 3 in the profile if it
                        // exists.
                        int acctCount = 0;
                        SizedSPropTagArray( 10, acctProps);

                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ID_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_TYPE_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_NAME_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ENABLE_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_USERNAME_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_URI_3;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3;
                        acctProps.cValues = acctCount;

                        result 
                            = lpServiceProfileObj->DeleteProps( 
                                    (LPSPropTagArray)&acctProps, NULL );          
                    }

                    // Account 4
                    if( conf->accounts.size() > 3 )
                    {
                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[3]->id.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ID_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_TYPE_4;
                        tempProps[ulProps++].Value.l = conf->accounts[3]->type;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                         MAX_PATH, "%S", 
                                conf->accounts[3]->name.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_NAME_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_DEFAULT_4;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[3]->defaultAccount;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_AB_ENABLE_4;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[3]->abEnabled;

                        tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_ENABLE_4;
                        tempProps[ulProps++].Value.b 
                            = conf->accounts[3]->enabled;

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[3]->user.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_USERNAME_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[3]->pass.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_PASSWORD_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                                conf->accounts[3]->uri.c_str());
						tempProps[ulProps].ulPropTag = PR_OTLKCON_ACCOUNT_URI_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);

                        _snprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, "%S", 
                            conf->accounts[3]->principleUri.c_str());
						tempProps[ulProps].ulPropTag 
                                        = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4;
                        tempProps[ulProps++].Value.lpszA = memObj._strdup(strBuff);
                    }
                    else
                    {
                        // Delete account 4 in the profile if it
                        // exists.
                        int acctCount = 0;
                        SizedSPropTagArray( 10, acctProps);

                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ID_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_TYPE_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_NAME_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_ENABLE_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_USERNAME_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_URI_4;
                        acctProps.aulPropTag[acctCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4;
                        acctProps.cValues = acctCount;

                        result 
                            = lpServiceProfileObj->DeleteProps( 
                                    (LPSPropTagArray)&acctProps, NULL );          
                    }

                    result = lpServiceProfileObj->SetProps(ulProps, tempProps, NULL);
					result = lpServiceProfileObj->SaveChanges(0);
                    ulProps = 0;

                    // Other properties
                    wcsncpy_s(otlkcon_logFile, conf->debugLogFilename.c_str(), MAX_PATH);
                    otlkcon_logToFileEnabled   = conf->debugFileEnabled;
                    otlkcon_logToSMEnabled     = conf->debugSMEnabled;
                    otlkcon_logToMSVCEnabled   = conf->debugDBEnabled;
                    otlkcon_debugLevel         = conf->debugLevel;
				}

                // Is this the first time the profile is being configured?
                if( profEID == NULL )
                {
                    O_ENTRYID* lpStoreEntryID = NULL;

                    result = otlkcon_generic_msgstore::CreateStoreEntryID(&lpStoreEntryID, &memObj);
                    if( result == S_OK )
                    {
                        // This store should be a MSP message store
                        lpStoreEntryID->supportedInterfaces |= OTLKCON_IMSPMSGSTORE_CLASS;
                        lpStoreEntryID->primarySupportedInterface = OTLKCON_IMSPMSGSTORE_CLASS;
                    }
                    else
                    {
                        OTLKCON_DEBUGBREAK;
                    }

                    tempProps[ulProps].ulPropTag = PR_RECORD_KEY;
					tempProps[ulProps].Value.bin.lpb = (LPBYTE)&lpStoreEntryID->storeInstanceGuid;//(LPBYTE)(profRecordKey?profRecordKey:&(msgstore->entryID->storeInstanceGuid));
					tempProps[ulProps++].Value.bin.cb  = sizeof(MAPIUID);

                    //We need to set entryID
					//to open existing store
					SBinary sbStoreEntryID;
					sbStoreEntryID.cb = sizeof(O_ENTRYID);
					sbStoreEntryID.lpb = (LPBYTE)lpStoreEntryID;

                    LPSPropValue lpStoreDll = NULL;
					result = HrGetOneProp(lpProfileObj, PR_PROVIDER_DLL_NAME, &lpStoreDll);
					
					result = WrapStoreEntryID(0, lpStoreDll->Value.lpszA,
						sbStoreEntryID.cb,
						(LPENTRYID)sbStoreEntryID.lpb,
						&sbWrappedEntryID.cb,
						(LPENTRYID*)&sbWrappedEntryID.lpb);

                    tempProps[ulProps].ulPropTag = PR_ENTRYID;
					tempProps[ulProps++].Value.bin = sbWrappedEntryID;

					tempProps[ulProps].ulPropTag = PR_PROVIDER_DISPLAY;
					tempProps[ulProps++].Value.lpszA = OTLKCON_STORE_DISPLAY_NAME_A;

					tempProps[ulProps].ulPropTag = PR_MDB_PROVIDER;
					tempProps[ulProps].Value.bin.lpb = (LPBYTE)&otlkcon_mdb_provider_guid;
					tempProps[ulProps++].Value.bin.cb  = sizeof(MAPIUID);
					
					tempProps[ulProps].ulPropTag = PR_DISPLAY_NAME;
					tempProps[ulProps++].Value.lpszA = OTLKCON_STORE_DISPLAY_NAME_A;

                    result = lpProfileObj->SetProps(ulProps, tempProps, NULL);
								lpProfileObj->SaveChanges(0);
					
					memObj.free(lpStoreEntryID);// delete msgstore;

                    ulProps = 0;
                }

                if( sbWrappedEntryID.lpb )
                {
					memObj.lpFreeBuffer(sbWrappedEntryID.lpb);
                }

				if(NULL != profProps)
				{
					memObj.lpFreeBuffer(profProps);
				} // if
				
				lpProfileObj->Release();
                lpServiceProfileObj->Release();
			}
            break;

        case MSG_SERVICE_CREATE:
			{
				result = MAPI_E_NOT_FOUND;
//            //    otlkcon_configure_gui(ulUIParam);
//            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
//                L"inside MSG_SERVICE_CREATE.\n");
//			MAPIUID uidRecordKey = {0};
//			lpMAPISup->NewUID(&uidRecordKey);
//
//			LPPROFSECT lpStoreSect = NULL;
//			result = OpenProviderProfileSection(lpProviderAdmin, MAPI_STORE_PROVIDER, &lpStoreSect);
//			if(SUCCEEDED(result))
//			{
//				//Set new Record key for the store
//				SPropValue spvRecordKey = {0};
//				spvRecordKey.ulPropTag = PR_RECORD_KEY;
//				spvRecordKey.Value.bin.cb = sizeof(MAPIUID);
//				spvRecordKey.Value.bin.lpb = (LPBYTE)&uidRecordKey;
//				result = lpStoreSect->SetProps(1, &spvRecordKey, NULL);
//				lpStoreSect->Release();
//			} // if
            //LoadBackendConfig("xml_backend.dll");
            //result = OTLKCON_ConfigureBackend(&configbe);
			}
            break;

        case MSG_SERVICE_DELETE:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
                L"inside MSG_SERVICE_DELETE.\n");
            break;

        case MSG_SERVICE_INSTALL:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
                L"inside MSG_SERVICE_INSTALL.\n");
            break;

        case MSG_SERVICE_UNINSTALL:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
                L"inside MSG_SERVICE_INSTALL.\n");
            break;

        case MSG_SERVICE_PROVIDER_DELETE:
            result = MAPI_E_NO_SUPPORT;
            break;

        case MSG_SERVICE_PROVIDER_CREATE:
            result = MAPI_E_NO_SUPPORT;
            break;

        default:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
                L"unknown service entry option.\n");
            result = MAPI_E_NO_SUPPORT;
    }

//    *lppMapiError = 0;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, L"leaving ServiceEntry.\n");

    return result;
}

HRESULT O_MessageServiceInit(LPALLOCATEBUFFER lpAllocateBuffer)
{
    HRESULT result = S_OK;
    HKEY hk;
    wchar_t szBuf[OTLKCON_REG_VALUE_MAX_LEN+1] = {0};
	DWORD szBufSize = OTLKCON_REG_VALUE_MAX_LEN;
	DWORD readRetVal = 0;

    /* Get registry settings */
    hk = otlkcon_registryInit(lpAllocateBuffer,0,NULL);
    if( hk != 0 )
    {
        otlkcon_debugLevel
                            = otlkcon_registryGetInt(hk, "debugLevel");
        otlkcon_logToFileEnabled
                            = otlkcon_registryGetInt(hk, "logToFileEnabled");
        otlkcon_logToMSVCEnabled
                            = otlkcon_registryGetInt(hk, "logToMSVCEnabled");
        otlkcon_logToSMEnabled
                            = otlkcon_registryGetInt(hk, "logToSMEnabled");

        szBufSize = OTLKCON_REG_VALUE_MAX_LEN;
        readRetVal = RegQueryValueExW(hk, L"logFile", NULL, NULL, (LPBYTE)otlkcon_logFile, &szBufSize);
	    if( readRetVal != ERROR_SUCCESS )
	    {
            wcsncpy_s( otlkcon_logFile, MAX_PATH+1, 
                    OTLKCON_LOG_DEFAULT_FILE, MAX_PATH );
	    }
    }
    otlkcon_registryDispose(hk);

    if( otlkcon_logToSMEnabled )
    {
#ifdef OTLKCON_LOG_SM_SUPPORT_ENABLED
        result = smlog_init(SMLOG_SM_DEFAULT_TIMEOUT, &otlkcon_processSMServerContext);
#else
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
            L"ERROR: Shared Memory Logging support not found.\n");
#endif /* OTLKCON_LOG_SM_SUPPORT_ENABLED */
    }

    srand((unsigned int)GetTickCount());

    return result;
}

HANDLE g_eventThreadHandle;

BOOL APIENTRY DllMain(
	HANDLE hModule, 
	DWORD  ul_reason_for_call, 
	LPVOID lpReserved
	)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
#ifdef _DEBUG
		_CrtSetDbgFlag(0);
#endif
      //  iRes = AllocProfilerInitAllocCheck();

		otlkcon_tlsIndex = TlsAlloc();
		//Initializing global objects
		InitializeCriticalSection(&otlkcon_sqlite_cs);
        InitializeCriticalSection(&otlkcon_objects_cs);

		InitializeCriticalSection(&otlkcon_stores_cs);
		InitializeCriticalSection(&otlkcon_store_providers_cs);
        InitializeCriticalSection(&otlkcon_xpp_wait_set_cs);
        
        //otlkcon_event_objects.push_back((void*)-1);

        // FIXME: Figure out impersonation issues

        // FIXME: MAPIInitialize order issues when we have a transport provider
        //        but no message store.
        g_eventThreadHandle = CreateThread(NULL, 0, otlkcon_event, 
                                            NULL, 0, &otlkcon_eventThreadId);
        if( g_eventThreadHandle == NULL )
        {
            OTLKCON_DEBUGBREAK;
        }

#ifdef OTLKCON_DEBUG_MEM_DB
        // Clear memory database debug file on every load.
        DeleteFile(OTLKCON_DEBUG_MEM_DB_FILENAME);
        Sleep( OTLKCON_DELETE_PAUSE );
#endif //OTLKCON_DEBUG_MEM_DB

	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		{
			//otlkcon_sqlite_helper * sqlObj = 
			//	(otlkcon_sqlite_helper *)TlsGetValue(otlkcon_tlsIndex);
			//if(NULL != sqlObj)
			//{
			//	//delete sqlObj;
			//	TlsSetValue(otlkcon_tlsIndex, NULL);
			//} // if
		}
		break;

	case DLL_PROCESS_DETACH:
		if(otlkcon_tlsIndex != (DWORD)-1) 
		{
			TlsFree(otlkcon_tlsIndex);
			otlkcon_tlsIndex = (DWORD)-1;
		} // if
		
		if(NULL != g_eventThreadHandle)
		{
			if(NULL != otlkcon_eventHwnd) 
			{
				PostMessage(otlkcon_eventHwnd, WM_QUIT, 0, 0);
			} // if

            // FIXME: We should use CreateEvent() and
            //        WaitForSingleObject() to signal
            //        thread termination.  Verifier goes
            //        crazy with the code below.
			Sleep(1000);
			TerminateThread(g_eventThreadHandle, -1);
			CloseHandle(g_eventThreadHandle);

		} // if

		//freeing global resources	
		DeleteCriticalSection(&otlkcon_sqlite_cs);

		DeleteCriticalSection(&otlkcon_stores_cs);
		DeleteCriticalSection(&otlkcon_store_providers_cs);
        DeleteCriticalSection(&otlkcon_xpp_wait_set_cs);

        //ulRes = AllocProfilerDeInitAllocCheck();
		break;
	}
	return TRUE;
}

STDINITMETHODIMP MSProviderInit(HINSTANCE hInstance,
                        LPMALLOC lpMalloc,
                        LPALLOCATEBUFFER lpAllocateBuffer,
                        LPALLOCATEMORE lpAllocateMore,
                        LPFREEBUFFER lpFreeBuffer,
                        ULONG ulFlags,
                        ULONG ulMAPIVer,
                        ULONG *lpulProviderVer,
                        LPMSPROVIDER *lppMSProvider)
{
    //debugObj.Initialize(lpAllocateBuffer, lpFreeBuffer);

	HRESULT result = S_OK;
    O_IMSProvider *msp;

    result = O_MessageServiceInit(lpAllocateBuffer);

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
        L"inside MSProviderInit.\n");

    if( ulMAPIVer < CURRENT_SPI_VERSION )
    {
        return MAPI_E_VERSION;
    }

    msp = new O_IMSProvider();
    otlkcon_memory *memObj 
        = new otlkcon_memory( lpAllocateBuffer, lpAllocateMore, lpFreeBuffer );
    msp->Create( memObj );
    msp->hInstance        = hInstance;

    *lpulProviderVer = CURRENT_SPI_VERSION;
    *lppMSProvider   = (LPMSPROVIDER)msp;

	//Henry 30.12.2005: idea is :every provider instance uses separate session per thread
	//maybe we can use the same index for all providers ?
	//Will try that
	//otlkcon_tlsIndex = TlsAlloc();

	OTLKCON_ENTERCRITICALSECTION(&otlkcon_store_providers_cs, "MSProviderInit");

	//registering provider in the table
	otlkcon_store_providers.push_back(msp);

	OTLKCON_LEAVECRITICALSECTION(&otlkcon_store_providers_cs, "MSProviderInit");
    
    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
        L"leaving MSProviderInit.\n");

	result = S_OK;
    return result;
}

#ifdef OTLKCON_AB

HRESULT ABProviderInit( 
    HINSTANCE hInstance,
    LPMALLOC lpMalloc,
    LPALLOCATEBUFFER lpAllocateBuffer,
    LPALLOCATEMORE lpAllocateMore,
    LPFREEBUFFER lpFreeBuffer,
    ULONG ulFlags,
    ULONG ulMAPIVer,
    ULONG *lpulProviderVer,
    LPABPROVIDER *lppABProvider  )
{
    HRESULT result = S_OK;
    O_IABProvider *abp;

    result = O_MessageServiceInit(lpAllocateBuffer);

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside ABProviderInit.\n");

    if( ulMAPIVer < CURRENT_SPI_VERSION )
    {
        return MAPI_E_VERSION;
    }

    abp = new O_IABProvider();
    otlkcon_memory *memObj 
        = new otlkcon_memory( lpAllocateBuffer, lpAllocateMore, lpFreeBuffer );
    result = abp->Create(memObj);

    *lpulProviderVer = CURRENT_SPI_VERSION;
    *lppABProvider = (LPABPROVIDER)abp;

    return result;
}

#endif // OTLKCON_AB

#ifdef OTLKCON_XP

HRESULT XPProviderInit(
  HINSTANCE hInstance,
  LPMALLOC lpMalloc,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  ULONG ulFlags,
  ULONG ulMAPIVer,
  ULONG *lpulProviderVer,
  LPXPPROVIDER *lppXPProvider  
)
{
    HRESULT result = S_OK;
    O_IXPProvider *xpp;

    result = O_MessageServiceInit(lpAllocateBuffer);

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
        L"inside XPProviderInit.\n");

    if( ulMAPIVer < CURRENT_SPI_VERSION )
    {
        return MAPI_E_VERSION;
    }

    xpp = new O_IXPProvider();
    otlkcon_memory *memObj 
        = new otlkcon_memory( lpAllocateBuffer, lpAllocateMore, lpFreeBuffer );
    result = xpp->Create(memObj);

    *lpulProviderVer = CURRENT_SPI_VERSION;
    *lppXPProvider = (LPXPPROVIDER)xpp;

    return result;
}

#endif /* OTLKCON_XP */

extern "C" void __declspec(naked) _cdecl _penter( void )
{
    _asm
    {
        push eax
        push ebx
        push ecx
        push edx
        push ebp
        push edi
        push esi
    }

//   OTLKCON_DEBUGBREAK;

    _asm
    {
        pop esi
        pop edi
        pop ebp
        pop edx
        pop ecx
        pop ebx
        pop eax
        ret
    }
}

HRESULT OpenProviderProfileSection(
	LPPROVIDERADMIN pAdminProvObj,
	ULONG			ulProviderType,
	LPPROFSECT *    ppProfSectObj
	)
{
	// Get the provider table where the settings are stored
	LPMAPITABLE pTableObj = NULL;
	HRESULT hResult = pAdminProvObj->GetProviderTable (0, &pTableObj);
	if (FAILED(hResult))
	{
		return hResult;
	}
	
	SizedSPropTagArray(2,sptProvider) = 
	{ 2, { PR_PROVIDER_UID, PR_RESOURCE_TYPE } };
	hResult = pTableObj->SetColumns ((LPSPropTagArray)&sptProvider, 0);

	if(SUCCEEDED(hResult))
	{
		SPropValue spvType = {0};
		spvType.ulPropTag = PR_RESOURCE_TYPE;
		spvType.Value.ul = ulProviderType;

		SRestriction srType = {0};
		srType.rt = RES_PROPERTY;
		srType.res.resProperty.relop = RELOP_EQ;
		srType.res.resProperty.ulPropTag = PR_RESOURCE_TYPE;
		srType.res.resProperty.lpProp = &spvType;

		hResult = pTableObj->Restrict(&srType, 0);
		if (SUCCEEDED(hResult))
		{
			// Query only one row, the user's row with the settings in it
			LPSRowSet pRows = NULL;
			hResult = pTableObj->QueryRows(1, 0, &pRows);
			if (SUCCEEDED(hResult))
			{
				hResult = pAdminProvObj->OpenProfileSection ((LPMAPIUID)pRows->aRow->lpProps->Value.bin.lpb,
					NULL,
					MAPI_MODIFY,
					ppProfSectObj);
				FreeProws (pRows);
				if (FAILED(hResult))
				{
					// Report failure, if any
					hResult = MAPI_E_NOT_FOUND;
				}
			} // if pTableObj->QueryRows
		} // if pTableObj->Restrict
	} // if pTableObj->SetColumns
	if(NULL != pTableObj)
	{
		pTableObj->Release();
	} // if
	return hResult;
}

HRESULT otlkcon_testDbFilename( char *fname, int *isValid )
{
    HRESULT result = S_OK;

    *isValid = 0;

    if ( fname && strlen(fname) )
    {
        //Check that the name is valid
        int pth = 0;
        errno_t err = _sopen_s(&pth, fname, 
            _O_CREAT|_O_RDWR|_O_BINARY, _SH_DENYNO, 
            _S_IREAD|_S_IWRITE);
        if( err==0 )
        {
            *isValid = 1;
            _close( pth );
        }
    }

    return result;
}

HRESULT otlkcon_getAccountsData(vector<otlkcon_account_details *> *accounts,
                                LPPROFSECT lpProfSectObj )
{
    HRESULT result = S_OK;
    ULONG profPropsCount = 0;
    LPSPropValue profProps;
    SizedSPropTagArray(60, profTags);
    wchar_t strBuff[MAX_PATH+1] = {0}; 

	memset(&profTags,0, sizeof(profTags));

    // Account info
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_USERNAME_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_1;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_1;

    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_USERNAME_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_2;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2;

    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_USERNAME_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_3;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3;

    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ID_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_TYPE_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_NAME_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_DEFAULT_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_ENABLE_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_AB_ENABLE_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_USERNAME_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PASSWORD_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_URI_4;
    profTags.aulPropTag[profPropsCount++] = PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4;
	profTags.cValues = profPropsCount;

    for( int i=0; i<OTLKCON_ACCOUNT_MAX; i++)
    {
        accounts->push_back( new otlkcon_account_details() );
    }

	result = lpProfSectObj->GetProps(
		(LPSPropTagArray)&profTags,
		0, &profPropsCount,
		&profProps);
	switch( result )
	{
	case MAPI_W_ERRORS_RETURNED:
	case S_OK:			
		for( ULONG i=0; i<profPropsCount; i++ )
		{
			// Account 1
            if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->id = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
				{
                    accounts->at(0)->type = profProps[i].Value.l;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1,
                                          MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->name = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->user = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->pass = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->uri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(0)->principleUri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(0)->enabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(0)->abEnabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_1) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(0)->defaultAccount 
                        = profProps[i].Value.b;
				}
			}// Account 2
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->id = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
				{
                    accounts->at(1)->type = profProps[i].Value.l;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->name = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->user = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->pass = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->uri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(1)->principleUri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(1)->enabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(1)->abEnabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_2) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(1)->defaultAccount 
                        = profProps[i].Value.b;
				}
			}// Account 3
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->id = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
				{
                    accounts->at(2)->type = profProps[i].Value.l;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->name = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->user = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->pass = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->uri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(2)->principleUri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(2)->enabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(2)->abEnabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_3) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(2)->defaultAccount 
                        = profProps[i].Value.b;
				}
			} //Account 4
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ID_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->id = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_TYPE_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_LONG )
				{
                    accounts->at(3)->type = profProps[i].Value.l;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_NAME_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->name = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_USERNAME_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->user = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PASSWORD_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->pass = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_URI_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->uri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_PRINCIPLE_URI_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
				{
                    _snwprintf_s( strBuff, MAX_PATH+1, MAX_PATH, L"%S", 
								profProps[i].Value.lpszA);
                    accounts->at(3)->principleUri = strBuff;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_ENABLE_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(3)->enabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_AB_ENABLE_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(3)->abEnabled = profProps[i].Value.b;
				}
			}
            else if( PROP_ID(profProps[i].ulPropTag) 
                                == PROP_ID(PR_OTLKCON_ACCOUNT_DEFAULT_4) )
			{
				if( PROP_TYPE(profProps[i].ulPropTag) == PT_BOOLEAN )
				{
                    accounts->at(3)->defaultAccount 
                        = profProps[i].Value.b;
				}
			}
		}
        break;

    default:
        // Error exit.
        goto getaccountsdata_end;   
    }

    result = S_OK;

getaccountsdata_end:
    return result;
}
